#include <iostream>
#include <fstream>
#include "pb_cfg_status.pb.h"
#include "CStatusMgr.h"
#include "../mainctrl.h"
#include "CUserStatus.h"
#include "commmsg.h"
#include "commclass.h"
#include "../data/CPlayerCacheData.h"
#include "MsgGM.pb.h"
#include "MsgAct.pb.h"
#include "MsgMapInfo.pb.h"
#include "../act/CActMgr.h"
#include "../map/CMapView.h"
#include "../battle/CBattleRole.h"
#include "../battle/CBattleRandom.h"
#include "../skill/CSkillAffect.h"
#include "../skill/CSkillEffect.h"
#include "../cmdinner/CCmdInnerActTitle.h"

int CStatusMgr::LoadConfig(const char* szCfgPath)
{
    int iRet = 0;
    int iIndex = 0;

    if (szCfgPath == NULL)
    {
        CT_ERROR(("Status Cfg Path is null"));
        return RET_SYSTEM_FAIL;
    }

    pb_cfg_status stStatusCfg;
    std::fstream stFileInput(szCfgPath, std::ios::in | std::ios::binary);
    if (!stStatusCfg.ParseFromIstream(&stFileInput))
    {
        CT_ERROR(("Failed to Parse StatusCfg!"));
        return RET_SYSTEM_FAIL;
    }

    CStatusCfgData stCfgData;
    unsigned int uiSkillEffectID = 0;
    unsigned int uiSkillAffectID = 0;
    CTLib::CTArray<unsigned int, MAX_STATUS_SKILL_AFF_COUNT> auiAffectID;
    CTLib::CTArray<unsigned int, MAX_STATUS_SKILL_COUNT> auiSkillID;

    for (int i = 0; i < stStatusCfg.status_cfg_rows_size(); ++i)
    {
        const pb_cfg_status_pb_cfg_status_cfg_unit& stStatusUnit 
            = stStatusCfg.status_cfg_rows(i);

        stCfgData.Clear();

        stCfgData.SetResID(stStatusUnit.res_id());
        stCfgData.SetType((char)stStatusUnit.type());
        stCfgData.SetActType(stStatusUnit.act_type());
        stCfgData.SetAddMax(stStatusUnit.add_max());
        stCfgData.SetTriggerWay(stStatusUnit.trigger_way());
        stCfgData.SetAppearType(stStatusUnit.appear_type());
        stCfgData.SetTriggerRate(stStatusUnit.trigger_rate());
        stCfgData.SetTriggerTime(stStatusUnit.trigger_time());
        stCfgData.SetValueType(stStatusUnit.value_type());
        stCfgData.SetData(stStatusUnit.data());
        stCfgData.SetAuxData(stStatusUnit.aux_data());
        stCfgData.SetBufferID(stStatusUnit.buffer_id());

        uiSkillEffectID = (unsigned int)stStatusUnit.skill_effect_id();
        if (uiSkillEffectID != 0)
        {
            iIndex =
                CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillEffCfg(
                        uiSkillEffectID);
            if (iIndex >= 0)
            {
                stCfgData.SetSkillEffect(uiSkillEffectID);
            }
            else
            {
                CT_ERROR(("skill effect(%u) empty when add status cfg(%d)",
                          uiSkillEffectID,stStatusUnit.res_id()));
                CT_RETURN(ERROR_SKILL_EFF_EMPTY_CFG);
            }
        }

        uiSkillAffectID = (unsigned int)stStatusUnit.skill_affect_id();
        if (uiSkillAffectID != 0)
        {
            iIndex =
                CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillAffCfg(
                        uiSkillAffectID);
            if (iIndex >= 0)
            {
                stCfgData.SetSkillAffect(uiSkillAffectID);
            }
            else
            {
                CT_ERROR(("skill affect(%u) empty when add status cfg(%d)",
                          uiSkillAffectID,stStatusUnit.res_id()));
                CT_RETURN(ERROR_SKILL_AFF_EMPTY_CFG);
            }
        }

        auiAffectID.Clear();
        auiAffectID.AddOneItem((unsigned int)stStatusUnit.skill_affect_id_1());
        auiAffectID.AddOneItem((unsigned int)stStatusUnit.skill_affect_id_2());
        auiAffectID.AddOneItem((unsigned int)stStatusUnit.skill_affect_id_3());
        for (int i = 0; i < auiAffectID.Size(); ++i)
        {
            if (auiAffectID[i] <= 0)
            {
                continue;
            }
            iIndex = CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillAffCfg(
                auiAffectID[i]);
            if (iIndex >= 0)
            {
                stCfgData.AddAffectID(auiAffectID[i]);
            }
            else
            {
                CT_ERROR(("skill affect(%u) empty when add status cfg(%d)",
                          auiAffectID[i],stStatusUnit.res_id()));
                CT_RETURN(ERROR_SKILL_AFF_EMPTY_CFG);
            }
        }

        auiSkillID.Clear();
        auiSkillID.AddOneItem((unsigned int)stStatusUnit.skill_id_1());
        auiSkillID.AddOneItem((unsigned int)stStatusUnit.skill_id_2());
        auiSkillID.AddOneItem((unsigned int)stStatusUnit.skill_id_3());

        for (int i = 0; i < auiSkillID.Size(); ++i)
        {
            if (auiSkillID[i] <= 0)
            {
                continue;
            }
            iIndex =
                CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillCfg(auiSkillID[i]);
            if (iIndex >= 0)
            {
                stCfgData.AddSkillID(auiSkillID[i]);
            }
            else
            {
                CT_ERROR(("skill (%u) empty when add status cfg(%d)",
                          auiSkillID[i],stStatusUnit.res_id()));
                CT_RETURN(ERROR_SKILL_EMPTY_CFG);
            }
        }

        iRet = _stStatusCfg.AddConfig(stCfgData);
        CT_RETURN(iRet);
    }

    //状态组配置
    CStatusGroup stGroupData;
    CTLib::CTArray<int, MAX_STATUS_GROUP_COUNT> aiStatusID;

    for (int i = 0; i < stStatusCfg.status_group_cfg_rows_size(); ++i)
    {
        const pb_cfg_status_pb_cfg_status_group_cfg_unit& stGroupUnit 
            = stStatusCfg.status_group_cfg_rows(i);

        stGroupData.Clear();

        stGroupData.SetResID(stGroupUnit.res_id());

        aiStatusID.Clear();
        aiStatusID.AddOneItem(stGroupUnit.status_id_1());
        aiStatusID.AddOneItem(stGroupUnit.status_id_2());
        aiStatusID.AddOneItem(stGroupUnit.status_id_3());
        aiStatusID.AddOneItem(stGroupUnit.status_id_4());
        aiStatusID.AddOneItem(stGroupUnit.status_id_5());
        aiStatusID.AddOneItem(stGroupUnit.status_id_6());
        aiStatusID.AddOneItem(stGroupUnit.status_id_7());
        aiStatusID.AddOneItem(stGroupUnit.status_id_8());
        aiStatusID.AddOneItem(stGroupUnit.status_id_9());
        aiStatusID.AddOneItem(stGroupUnit.status_id_10());

        for (int i = 0; i < aiStatusID.Size(); ++i)
        {
            if (aiStatusID[i] <= 0)
            {
                continue;
            }
            iIndex = FindStatusCfg(aiStatusID[i]);
            if (iIndex >= 0)
            {
                stGroupData.AddStatusID(aiStatusID[i]);
            }
            else
            {
                CT_ERROR(("status(%d) empty when add status group cfg(%d)",
                          aiStatusID[i],stGroupUnit.res_id()));
                CT_RETURN(ERROR_STATUS_EMPTY_CFG);
            }
        }

        iRet = _stStatusCfg.AddGroupConfig(stGroupData);
        CT_RETURN(iRet);
    }

    return 0;
}

int CStatusMgr::FindStatus(CPlayerCacheData& stPlayerCache, int iResID)
{
    return stPlayerCache._stUserStatus.FindStatus(iResID);
}

CStatusUnit& CStatusMgr::GetStatus(CPlayerCacheData& stPlayerCache, int iIndex)
{
    return stPlayerCache._stUserStatus.GetStatus(iIndex);
}

int CStatusMgr::FindStatus(CStatusList& stStatusList, int iResID)
{
    for (int i = 0; i < stStatusList._astStatus.Size(); ++i)
    {
        if (iResID == stStatusList._astStatus[i]._iResID)
        {
            return i;
        }
    }

    return -1;
}

bool CStatusMgr::IsNeedSendStatusList(int iStatusID)
{
    int iIndex = 0;
    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_ERROR(("status(%d) config can not find!",iStatusID));
        return false;
    }

    CStatusCfgData& stStatusCfgData = GetStatusCfg(iIndex);

    if (stStatusCfgData.GetBufferID() > 0)
    {
        return true;
    }

    return false;
}

int CStatusMgr::DelStatus(CPlayerCacheData& stPlayerCache, int iStatusID,
        bool bSendStatusList)
{
    int iRet = 0;
    iRet = stPlayerCache._stUserStatus.DelStatus(iStatusID);
    if (iRet)
    {
        CT_WARNING(("role(%u) delete status(%d) error(%d)",
                    stPlayerCache._uiGID,iStatusID,iRet));
        return iRet;
    }

    if (bSendStatusList)
    {
        if (IsNeedSendStatusList(iStatusID))
        {
            NotifyUserStatusToSelfByGID(stPlayerCache._uiGID);
        }
    }

    return iRet;
}

//状态不存在则增加 状态已存在则增加叠加数 不超过叠加上限
int CStatusMgr::AddStatus(CPlayerCacheData& stPlayerCache, int iStatusID,
        int iEndTime, short shActID, bool bSendStatusList)
{
    int iRet = 0;
    int iIndex = 0;

    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        return ERROR_STATUS_EMPTY_CFG;
    }
    CStatusCfgData& stStatusCfg = GetStatusCfg(iIndex);

    iIndex = FindStatus(stPlayerCache, iStatusID);
    if (iIndex < 0)
    {
        CStatusUnit stStatusUnit;
        stStatusUnit.SetResID(iStatusID);
        stStatusUnit.SetActID(shActID);
        stStatusUnit.SetEndTime(iEndTime);
        stStatusUnit.SetAddNum(1);
        iRet = stPlayerCache._stUserStatus.AddStatus(stStatusUnit);
        CT_RETURN(iRet);
    }
    else
    {
        CStatusUnit& stStatusUnit = GetStatus(stPlayerCache, iIndex);
        if (stStatusUnit.GetResID() != iStatusID)
        {
            stStatusUnit.SetResID(iStatusID);
        }
        stStatusUnit.SetEndTime(iEndTime);
        if (stStatusCfg.GetAddMax() > 0 &&
            stStatusUnit.GetAddNum() >= stStatusCfg.GetAddMax())
        {
            stStatusUnit.SetAddNum(stStatusCfg.GetAddMax());
        }
        else
        {
            stStatusUnit.SetAddNum(stStatusUnit.GetAddNum() + 1);
        }
    }

    if (bSendStatusList)
    {
        if (IsNeedSendStatusList(iStatusID))
        {
            NotifyUserStatusToSelfByGID(stPlayerCache._uiGID);
        }
    }

    return 0;
}

//状态不存在则增加 状态已存在则增加叠加数 不超过叠加上限 此增加要求存在skill id
int CStatusMgr::AddStatus(CStatusList& stStatusList, int iStatusID, int iAddNum,
        int iActType)
{
    int iRet = 0;
    int iIndex = 0;

    iIndex = FindSkillAffect(iStatusID);
    if (iIndex < 0)
    {
        CT_WARNING(("status(%d) do not have skill affect, fail to add to list",
            iStatusID));
        return 0;
    }

    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_ERROR(("status(%d) config empty",iStatusID));
        return ERROR_STATUS_EMPTY_CFG;
    }
    CStatusCfgData& stStatusCfg = GetStatusCfg(iIndex);

    if (stStatusCfg.GetActType() != 0 && stStatusCfg.GetActType() != iActType)
    {
        CT_TRACE(("status(%d) act type(%d) but given act type(%d)",
            iStatusID,stStatusCfg.GetActType(),iActType));
        return 0;
    }

    //非功能性(没有skill id)则剔除
    if (stStatusCfg.GetSkillIDSize() <= 0 && stStatusCfg.GetSkillAffect() <= 0)
    {
        CT_TRACE(("status(%d) empty affect or skill won't add to statuslist",
            iStatusID));
        return 0;
    }

    if (iAddNum <= 0)
    {
        iAddNum = 1;
    }

    int iAddMax = stStatusCfg.GetAddMax();
    if (iAddMax > 0 && iAddNum >= iAddMax)
    {
        iAddNum = iAddMax;
    }

    iIndex = FindStatus(stStatusList, iStatusID);
    if (iIndex < 0)
    {
        CStatusObj stStatusObj;
        stStatusObj._iResID = iStatusID;
        stStatusObj._iAddNum = iAddNum;
        iRet = stStatusList._astStatus.AddOneItem(stStatusObj);
        if (iRet < 0)
        {
            CT_WARNING(("status list add object(%d) error(%d)",iStatusID,iRet));
        }
    }
    else
    {
        CStatusObj& stStatusObj = stStatusList._astStatus[iIndex];
        if (stStatusObj._iResID != iStatusID)
        {
            stStatusObj._iResID = iStatusID;
        }

        if (iAddMax > 0 &&
            stStatusObj._iAddNum + iAddNum >= iAddMax)
        {
            stStatusObj._iAddNum = iAddMax;
        }
        else
        {
            stStatusObj._iAddNum += iAddNum;
        }
    }

    return 0;
}

int CStatusMgr::FindCfgSkillEffect(int iStatusID)
{
    int iIndex = 0;
    unsigned int uiSkillEffectID = 0;
    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_WARNING(("find status(%d) config error(%d)", iStatusID, iIndex));
        return -1;//因为返回下标 所以这里必须返回负数
    }

    CStatusCfgData& stStatusCfgData = GetStatusCfg(iIndex);

    uiSkillEffectID = stStatusCfgData.GetSkillEffect();

    if (uiSkillEffectID <= 0)
    {
        return -1;//因为返回下标 所以这里必须返回负数
    }

    iIndex =
        CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillEffCfg(uiSkillEffectID);
    if (iIndex < 0)
    {
        CT_WARNING(("status(%d) config skill effect(%u) error(%d)",
                    iStatusID, uiSkillEffectID, iIndex));
        return -1;//因为返回下标 所以这里必须返回负数
    }
        
    return iIndex;
}

CSkillEffect& CStatusMgr::GetCfgSkillEffect(int iIndex)
{
    return CMainCtrl::m_pstMain->m_stSkillMgr.GetSkillEffCfg(iIndex);
}

int CStatusMgr::FindSkillAffect(int iStatusID)
{
    int iIndex = 0;
    unsigned int uiSkillAffectID = 0;
    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_WARNING(("find status(%d) config error(%d)", iStatusID, iIndex));
        return -1;//因为返回下标 所以这里必须返回负数
    }

    CStatusCfgData& stStatusCfgData = GetStatusCfg(iIndex);

    uiSkillAffectID = stStatusCfgData.GetSkillAffect();

    if (uiSkillAffectID <= 0)
    {
        return -1;//因为返回下标 所以这里必须返回负数
    }

    iIndex =
        CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillAffCfg(uiSkillAffectID);
    if (iIndex < 0)
    {
        CT_WARNING(("status(%d) config skill affect(%u) error(%d)",
                    iStatusID, uiSkillAffectID, iIndex));
        return -1;//因为返回下标 所以这里必须返回负数
    }
        
    return iIndex;
}

CSkillAffect& CStatusMgr::GetSkillAffect(int iIndex)
{
    return CMainCtrl::m_pstMain->m_stSkillMgr.GetSkillAffCfg(iIndex);
}

unsigned int CStatusMgr::GetBufferID(int iStatusID)
{
    int iIndex = 0;
    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_WARNING(("status(%d) config empty!",iStatusID));
        return 0;
    }

    CStatusCfgData& stCfgData = GetStatusCfg(iIndex);

    return stCfgData.GetBufferID();
}

//只取第1个skill effect的数值
int CStatusMgr::FindSkillEffect(int iStatusID)
{
    int iIndex = 0;
    iIndex = FindSkillAffect(iStatusID);
    if (iIndex < 0)
    {
        return -1;//因为返回下标 所以这里必须返回负数
    }

    CSkillAffect& stSkillAffect = GetSkillAffect(iIndex);

    int iEffectSize = stSkillAffect.GetSkillEffectSize();
    if (iEffectSize <= 0)
    {
        CT_WARNING(("status(%d) config skill affect empty",iStatusID));
        return -1;//因为返回下标 所以这里必须返回负数
    }

    unsigned int uiEffectID = stSkillAffect.GetSkillEffectID(0);

    iIndex = CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillEffCfg(uiEffectID);
    if (iIndex < 0)
    {
        CT_WARNING(("status(%d) skill effect(%u) empty",iStatusID,uiEffectID));
        return -1;//因为返回下标 所以这里必须返回负数
    }

    return iIndex;
}

CSkillEffect& CStatusMgr::GetSkillEffect(int iIndex)
{
    return CMainCtrl::m_pstMain->m_stSkillMgr.GetSkillEffCfg(iIndex);
}

int CStatusMgr::GetStatusAttr(CUserStatus& stUserStatus,
        CPlayerAttr& stPlayerAttr)
{
    return stUserStatus.CalcStatusAddAttr(stPlayerAttr);
}

int CStatusMgr::CalcStatusAddAttr(MAP_GRID_MULTI& stMapGridMulti,
        CSkillAffect& stSkillAffect, CStatusObj& stStatusObj)
{
    int iBattleID = 0;

    CT_BATTLE(("输出计算状态加成属性的目标列表"));
    DumpStatusTarget(stMapGridMulti);

    for(int i = 0; i < stMapGridMulti.Size(); ++i)
    {
        iBattleID = stMapGridMulti[i].GetRoleID();
        if (!CMainCtrl::m_pstMain->m_stBattleMgr.IsValidRoleID(iBattleID))
        {
            CT_WARNING(("battle role id(%d) invalid",iBattleID));
            continue;
        }

        CBattleRole& stBattleRole =
            CMainCtrl::m_pstMain->m_stBattleMgr.GetBattleRole(iBattleID);

        CT_BATTLE(("个体(%d)基础属性：",iBattleID));
        CMainCtrl::m_pstMain->m_stBattleMgr.DumpPlayerAttr(stBattleRole.GetBaseAttr());

        CT_BATTLE(("个体(%d)加成前的战斗属性：",iBattleID));
        CMainCtrl::m_pstMain->m_stBattleMgr.DumpPlayerAttr(stBattleRole.GetBattleAttr());

        CalcStatusAddAttr(stSkillAffect, stBattleRole.GetBattleAttr(),
                stBattleRole.GetBaseAttr(), stStatusObj);

        CT_BATTLE(("个体(%d)加成后的战斗属性：",iBattleID));
        CMainCtrl::m_pstMain->m_stBattleMgr.DumpPlayerAttr(stBattleRole.GetBattleAttr());
    }

    return 0;
}

int CStatusMgr::CalcStatusAddAttr(CSkillAffect& stSkillAffect,
      CPlayerAttr& stNewAttr, CPlayerAttr& stBaseAttr, CStatusObj& stStatusObj)
{
    int iChgValue = 0;
    unsigned char ucStatType = 0;
    unsigned char ucSubType = 0;

    for (int i = 0; i < stSkillAffect.GetSkillEffectSize(); ++i)
    {
        CSkillEffect& stSkillEffect = stSkillAffect.GetSkillEffect(i);
        ucStatType = stSkillEffect.GetStatType();
        ucSubType = stSkillEffect.GetSubType();
        iChgValue = 0;
        if (ucStatType == CSkillEffect::SKILL_STAT_BUFF_1 ||
            ucStatType == CSkillEffect::SKILL_STAT_DEBUFF_1 ||
            ucStatType == CSkillEffect::SKILL_STAT_BUFF_2 ||
            ucStatType == CSkillEffect::SKILL_STAT_DEBUFF_2 ||
            ucStatType == CSkillEffect::SKILL_STAT_BUFF_3 ||
            ucStatType == CSkillEffect::SKILL_STAT_DEBUFF_3 ||
            ucStatType == CSkillEffect::SKILL_STAT_BUFF_TREASURE ||
            ucStatType == CSkillEffect::SKILL_STAT_BUFF_MOUNT)
        {
            CMainCtrl::m_pstMain->m_stBattleMgr.SkillPreEffectDataCalc(
                    iChgValue, stBaseAttr.GetAttr(ucSubType), stSkillEffect);

            iChgValue = stNewAttr.GetAttr(ucSubType) +
                iChgValue * stStatusObj._iAddNum;
            //不要修正为非负
            stNewAttr.SetAttr(ucSubType, iChgValue);
        }
    }

    return 0;
}

int CStatusMgr::GetStatusList(int iStatusGroupID, CStatusList& stStatusList)
{
    int iIndex = 0;
    int iStatusID = 0;

    if (iStatusGroupID <= 0)
    {
        return 0;
    }

    iIndex = FindStatusGroup(iStatusGroupID);
    if (iIndex < 0)
    {
        CT_WARNING(("status group(%d) config empty",iStatusGroupID));
        return ERROR_STATUS_GROUP_EMPTY_CFG;
    }

    CStatusGroup& stStatusGroup = GetStatusGroup(iIndex);

    for (int i = 0; i < stStatusGroup.GetStatusIDSize(); ++i)
    {
        iStatusID = stStatusGroup.GetStatusID(i);
        if (iStatusID > 0)
        {
            AddStatus(stStatusList, iStatusID, 1, 0);
        }
        else
        {
            CT_WARNING(("status(%d) id invalid",iStatusID));
        }
    }

    return 0;
}

int CStatusMgr::GetStatusList(unsigned int uiGID, CStatusList& stStatusList,
        int iActType)
{
    int iIndex = 0;

    iIndex = CMainCtrl::m_pstMain->FindPlayerCacheData(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("no cache data user %u", uiGID));
        return 0;
    }

	CPlayerCacheData& stPlayerCache =
        CMainCtrl::m_pstMain->m_stPlayerCacheDataHash[iIndex];

    return stPlayerCache._stUserStatus.GetStatusList(stStatusList, iActType);
}

int CStatusMgr::GMDealStatus(CPlayerCacheData& stPlayerCache,
        MsgReqGMPlayer& stReq, MsgAnsGMPlayer& stAns)
{
    int iRet = 0;
    switch (stReq.sub_type())
    {
    case ID_GM_PLAYER_SUB_GET_STATUS:
        {
            iRet = stPlayerCache._stUserStatus.GMStatusList(stAns);
        }
        break;
    case ID_GM_PLAYER_SUB_ADD_STATUS:
        {
#define STATUS_DEFAULT_EXPIRE_TIME 3600
            short shStatudID = 0;
            int iEndTime = CMainCtrl::m_pstMain->m_iNow;
            if (stReq.datas_size() == 1)
            {
                shStatudID = (short)(stReq.datas(0) & 0x7FFF);
                iEndTime += STATUS_DEFAULT_EXPIRE_TIME;
            }
            else if (stReq.datas_size() >= 2)
            {
                shStatudID = (short)(stReq.datas(0) & 0x7FFF);
                if (stReq.datas(1) > 0)
                {
                    iEndTime += stReq.datas(1);
                }
                else
                {
                    iEndTime += STATUS_DEFAULT_EXPIRE_TIME;
                }
            }

            iRet = AddStatus(stPlayerCache, shStatudID, iEndTime, 0, true);
            if (!iRet)
            {
                iRet = stPlayerCache._stUserStatus.GMStatusList(stAns);
            }
        }
        break;
    default:
        return ERROR_MAIN_SUB_CMD;
    }

    return iRet;
}

//作为获取角色状态列表和冥想的唯一数据构建接口
void CStatusMgr::GetUserStatus(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerCacheData& stPlayerCache, MsgAnsMapInfo& stMsgAnsMap)
{
    bool bHasChg = false;
    stPlayerCache._stUserStatus.UpdateUserStatus(bHasChg);
    stPlayerCache._stUserStatus.GetUserStatus(stMsgAnsMap);

    stMsgAnsMap.set_is_musing(stPlayerDetail._stMuseData.IsMusing());
}

//作为获取角色状态列表和冥想以及称号列表的唯一数据构建接口
void CStatusMgr::GetUserStatusAndTitle(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerCacheData& stPlayerCache, CPlayerSnsCommInfo& stPlayerSnsComm,
        MsgAnsMapInfo& stMsgAnsMap, bool bResetPosInfo)
{
    if (bResetPosInfo)
    {
        MsgUserPos* pstAnsMapPos = stMsgAnsMap.mutable_pos();
        if (pstAnsMapPos)
        {
            pstAnsMapPos->set_map_id(stPlayerOnline._uiNowMapID);
            pstAnsMapPos->set_pos_x(
                ((stPlayerOnline._usMapPosX==0xFFFF)
                    ? -1 : stPlayerOnline._usMapPosX));
            pstAnsMapPos->set_pos_y(
                ((stPlayerOnline._usMapPosY==0xFFFF)
                    ? -1 : stPlayerOnline._usMapPosY));
        }
        else
        {
            CT_ERROR(("MsgUserPos pointer null!"));
        }
    }

    //称号列表隐藏在MsgRoleInfo中这里整个结构下发建议类似状态列表一样独立一个称号列表
    CMainCtrl::m_pstMain->m_stRoleMgr.CopyRoleInfo(stPlayerBase, stPlayerDetail,
        stPlayerOnline, stPlayerSnsComm, *(stMsgAnsMap.mutable_role()));

    //角色状态列表和冥想
    GetUserStatus(stPlayerBase, stPlayerDetail, stPlayerOnline, stPlayerCache,
         stMsgAnsMap);

    int iIndex = 0;
    unsigned int uiFrontBuffID = 0;
    unsigned int uiAuctionKingGID =
        CMainCtrl::m_pstMain->m_stZoneOnlineData._stZoneData._stAuctionZoneData._uiKingGid; 
    do{
        iIndex = CMainCtrl::m_pstMain->m_stClanMgr.GetClanIndex(
            stPlayerDetail._uiGID);
        if (iIndex < 0)
        {
            CT_TRACE(("gid = %u not in any Clan",stPlayerDetail._uiGID));
            break;
        }
        CClanEntry& stClanEntry =
            CMainCtrl::m_pstMain->m_stClanMgr._stClanEntryHash[iIndex];
        
        if (stPlayerDetail._stUserClan._uiClanId != stClanEntry._uiClanId)
        {
            CT_ERROR(("clan entry id(%u) role(%u) clan detail user clan id(%u)",
                      stClanEntry._uiClanId,stPlayerDetail._uiGID,
                      stPlayerDetail._stUserClan._uiClanId));
            break;
        }
    
        //家族被动技能
        uiFrontBuffID = GetBufferID(CStatusUnit::STATUS_ID_CLAN_PASSIVE_SKILL);
        if (uiFrontBuffID > 0)
        {
            MsgUserStatus* pstMsgStatusUnit = stMsgAnsMap.add_status();
            if (!pstMsgStatusUnit){CT_WARNING(("pb pointer null!"));break;}
            
            pstMsgStatusUnit->set_status_id(uiFrontBuffID);
            MsgKeyValueUnit* pstMsgKeyValueUnit =
                pstMsgStatusUnit->add_key_value();
            if (!pstMsgKeyValueUnit){CT_WARNING(("pb pointer null!"));break;}
            pstMsgKeyValueUnit->set_key(0);
            pstMsgKeyValueUnit->set_value(stClanEntry._ucClanLevel);
        }

        //家族拍卖王状态
        uiFrontBuffID = GetBufferID(CStatusUnit::STATUS_ID_CLAN_AUCTION_KING);
        if (uiFrontBuffID > 0 && uiAuctionKingGID > 0 &&
            stClanEntry._iAuctionBuffTime > CMainCtrl::m_pstMain->m_iNow)
        {
            MsgUserStatus* pstMsgStatusUnit = stMsgAnsMap.add_status();
            if (!pstMsgStatusUnit){CT_WARNING(("pb pointer null!"));break;}
            
            pstMsgStatusUnit->set_status_id(uiFrontBuffID);
            pstMsgStatusUnit->set_expire_time(stClanEntry._iAuctionBuffTime);
            pstMsgStatusUnit->set_status_tip(
                CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(uiAuctionKingGID));
            MsgKeyValueUnit* pstMsgKeyValueUnit =
                pstMsgStatusUnit->add_key_value();
            if (!pstMsgKeyValueUnit){CT_WARNING(("pointer!!!"));continue;}
            pstMsgKeyValueUnit->set_key(0);
            pstMsgKeyValueUnit->set_value(CLAN_AUCTION_SILVER_ADDITION);
        }

        //家族主动技能
        uiFrontBuffID = GetBufferID(CStatusUnit::STATUS_ID_CLAN_ACTIVE_SKILL);
        CUserClan::T_CLAN_SKILL astClanSkill; //先判断有没有学习了的家族技能
        CMainCtrl::m_pstMain->m_stClanMgr.GetSkillStatusAttr(
            stPlayerDetail._stUserClan, astClanSkill);
        if (uiFrontBuffID > 0 && astClanSkill.Size() > 0)
        {
            MsgUserStatus* pstMsgStatusUnit = stMsgAnsMap.add_status();
            if (!pstMsgStatusUnit){CT_WARNING(("pb pointer null!"));break;}
            
            pstMsgStatusUnit->set_status_id(uiFrontBuffID);

            for (int i = 0; i < astClanSkill.Size(); ++i)
            {
                MsgKeyValueUnit* pstMsgKeyValueUnit =
                    pstMsgStatusUnit->add_key_value();
                if (!pstMsgKeyValueUnit){CT_WARNING(("pointer!!!"));continue;}
                pstMsgKeyValueUnit->set_key(astClanSkill[i]._ucType);
                pstMsgKeyValueUnit->set_value(astClanSkill[i]._iValue);
            }
        }
    }while(0);
}

void CStatusMgr::NotifyUserStatusToMapByGID(unsigned int uiGID)
{
    CCmdInnerActTitle* pstCmd =
        (CCmdInnerActTitle*)CT_CMDFACTORY->CreateCmd(ID_MAIN_INNER_ACT_TITLE);
    if (!pstCmd){CT_ERROR(("create CCmdInnerActTitle error %u",uiGID));return;}

    pstCmd->pstMainCtrl = CMainCtrl::m_pstMain;
    pstCmd->_uiGID = uiGID;
    pstCmd->_iSubCmd = CActMgr::CMD_ACT_OPT_SUB_NOTIFY_STATUS_TO_MAP;
    pstCmd->Do(NULL);
}

void CStatusMgr::NotifyUserStatusToMap(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerCacheData& stPlayerCache, CPlayerSnsCommInfo& stPlayerSnsComm)
{
    MsgAnsMapInfo stMsgAnsMap;
    stMsgAnsMap.set_gid(stPlayerCache._uiGID);

    GetUserStatusAndTitle(stPlayerBase, stPlayerDetail, stPlayerOnline,
        stPlayerCache, stPlayerSnsComm, stMsgAnsMap, true);

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();

    PBMsgHead stMsgHead;

    stMsgHead.set_version(0);
    stMsgHead.set_time(CMainCtrl::m_pstMain->m_iNow);
    stMsgHead.set_msgact(0);
    stMsgHead.set_msgid(ID_MAIN_GET_MAP_INFO);
    stMsgHead.set_msgret(0);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead,
        CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgAnsMap,
        CMainCtrl::m_pstMain->m_stEncodeBuf);

    CSingleMapView::MAP_VIEW_NOTIFY_USERS_ARRAY auiMapUserList;
    CMainCtrl::m_pstMain->m_stMapViews.GetMapUsers(stPlayerOnline._uiNowMapID,
        stPlayerCache._uiGID, auiMapUserList);

    for (int i = 0; i < auiMapUserList.Size(); ++i)
    {
        CMainCtrl::m_pstMain->NotifyOnlineUser(auiMapUserList[i],
            CMainCtrl::m_pstMain->m_stEncodeBuf);
    }
}

//因为涉及很多需要准备的数据 创建命令自己准备
void CStatusMgr::NotifyUserStatusToSelfByGID(unsigned int uiGID)
{
    CCmdInnerActTitle* pstCmd =
        (CCmdInnerActTitle*)CT_CMDFACTORY->CreateCmd(ID_MAIN_INNER_ACT_TITLE);
    if (!pstCmd){CT_ERROR(("create CCmdInnerActTitle error %u",uiGID));return;}

    pstCmd->pstMainCtrl = CMainCtrl::m_pstMain;
    pstCmd->_uiGID = uiGID;
    pstCmd->_iSubCmd = CActMgr::CMD_ACT_OPT_SUB_NOTIFY_STATUS_TO_SELF;
    pstCmd->Do(NULL);
}

void CStatusMgr::NotifyUserStatusToSelf(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerCacheData& stPlayerCache, CPlayerSnsCommInfo& stPlayerSnsComm)
{
    MsgAnsMapInfo stMsgAnsMap;
    stMsgAnsMap.set_gid(stPlayerCache._uiGID);

    GetUserStatusAndTitle(stPlayerBase, stPlayerDetail, stPlayerOnline,
        stPlayerCache, stPlayerSnsComm, stMsgAnsMap, true);

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();

    PBMsgHead stMsgHead;

    stMsgHead.set_version(0);
    stMsgHead.set_time(CMainCtrl::m_pstMain->m_iNow);
    stMsgHead.set_msgact(0);
    stMsgHead.set_msgid(ID_MAIN_GET_MAP_INFO);
    stMsgHead.set_msgret(0);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead,
        CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgAnsMap,
        CMainCtrl::m_pstMain->m_stEncodeBuf);

    CMainCtrl::m_pstMain->NotifyOnlineUser(stPlayerCache._uiGID,
        CMainCtrl::m_pstMain->m_stEncodeBuf);
}

void CStatusMgr::NotifyUserStatusToClanMember(unsigned int uiClanID)
{
    int iIndex = 0;

    //检查家族是否存在
    iIndex = CMainCtrl::m_pstMain->m_stClanMgr._stClanEntryHash.HashFind(
        uiClanID);
    if (iIndex < 0)
    {
        CT_WARNING(("clan(%u) member not exist!",uiClanID));
        return;
    }
    CClanEntry& stClanEntry =
        CMainCtrl::m_pstMain->m_stClanMgr._stClanEntryHash[iIndex];

    for (int i = 0; i < stClanEntry._astClanMember.Size(); ++i)
    {
        if (!CMainCtrl::m_pstMain->m_stPlayerOnline.CheckOnline(
                stClanEntry._astClanMember[i]._uiGid))
        {
            CT_TRACE(("clan(%u %s) notify magic door act member(%u) offline",
                stClanEntry._uiClanId,stClanEntry._szName(),
                stClanEntry._astClanMember[i]._uiGid));
            continue;
        }

        NotifyUserStatusToSelfByGID(stClanEntry._astClanMember[i]._uiGid);
    }
}

void CStatusMgr::UpdateUserStatus(CPlayerBaseInfo& stPlayerBase,
        CPlayerDetailInfo& stPlayerDetail, CPlayerOnlineData& stPlayerOnline,
        CPlayerCacheData& stPlayerCache, CPlayerSnsCommInfo& stPlayerSnsComm,
        CPlayerDetailInfoEx1& stPlayerDetailEx1, int iTimeGap)
{
    bool bHasChg = false;
    bool bWingChg = false;

    iTimeGap = iTimeGap < 0 ? 0 : iTimeGap;

    if (CMainCtrl::m_pstMain->m_iNow <=
            stPlayerCache._stUserStatus.GetLastUpdateTime() + iTimeGap)
    {
        return;
    }

    if (stPlayerOnline._uiNowWing > 0)
    {
        if (CMainCtrl::m_pstMain->m_iNow >
                stPlayerDetailEx1._stUserFasion.GetWingEndTime(
                    stPlayerOnline._uiNowWing))
        {
            bWingChg = true;
            stPlayerOnline._uiNowWing = 0;
            CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBase._uiGID,
                NOTIFY_ROLE_ATTR);
        }
    }

    stPlayerCache._stUserStatus.UpdateUserStatus(bHasChg);

    if (!bHasChg && !bWingChg)
    {
        return;
    }

    MsgAnsMapInfo stMsgAnsMap;
    stMsgAnsMap.set_gid(stPlayerCache._uiGID);

    GetUserStatusAndTitle(stPlayerBase, stPlayerDetail, stPlayerOnline,
        stPlayerCache, stPlayerSnsComm, stMsgAnsMap, true);

    CMainCtrl::m_pstMain->NotifyOnlineUser(stPlayerCache._uiGID,
        ID_MAIN_GET_MAP_INFO, stMsgAnsMap, false);
}

int CStatusMgr::StatusBattleVideo(CStatusCfgData& stCfgData,
        CBattleRole& stBattleRole, CBattleRole& stBattleTarget,
        CStatusObj& stStatusObj, bool& bHaveTriggerVideo)
{
    if (STATUS_SOURCE_OBJ_TREASURE != stStatusObj._iSrcType)
    {
        return 0;
    }

    int iIndex = 0;
    int iStatusID = stStatusObj._iResID;
    int iTreasureID = (int)stStatusObj._uiSrcResID;

    //部分秘宝至多输出一次日志
    switch (iTreasureID)
    {
    case CTreasureMgr::TREASURE_CFG_ID_LOW_BLOOD://时间沙漏
        {
            if (stStatusObj._iAuxData > 0)
            {
                return 0;
            }
        }
    default:
        break;
    }

    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_RETURN(ERROR_STATUS_EMPTY_CFG);
    }

    CStatusCfgData& stConfigData = GetStatusCfg(iIndex);

    iIndex = FindSkillEffect(iStatusID);
    if (iIndex < 0)
    {
        CT_RETURN(ERROR_STATUS_SKILL_EFF_EMPTY);
    }

    CSkillEffect& stSkillEffect = GetSkillEffect(iIndex);

    int iBaseVal = 0;
    int iChgByLvl = 0;

    switch (iTreasureID)
    {
    case CTreasureMgr::TREASURE_CFG_ID_SELF_ANGER://隆基努斯长矛
        {
            iBaseVal = 0;
            iChgByLvl = stStatusObj._iAuxData * stSkillEffect.GetData();
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_ENEMY_HP://断钢巨剑
        {
            iBaseVal = stConfigData.GetData();
            iChgByLvl = stSkillEffect.GetData();
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_BEING_ATK://恶魔之牙
        {
            iBaseVal = 0;
            iChgByLvl = stSkillEffect.GetData();
            if (iChgByLvl < 0)
            {
                iChgByLvl = 0 - iChgByLvl;//策划要求此值处理为正值
            }
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_ENEMY_DIE://诺顿剑
        {
            iBaseVal = 0;
            iChgByLvl = stSkillEffect.GetData() * (stStatusObj._iAuxData - 1);
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_GROUP_ATK://圣洁圣杯
        {
            int iDistance = stBattleTarget.GetGridIndex() -
                    stBattleRole.GetGridIndex();
            if (iDistance < 0)
            {
                iDistance = 0 - iDistance;
            }
            else if (0 == iDistance)
            {
                CT_WARNING(("role(%d) target(%d) distance 0 when treasure(%d)",
                            stBattleRole.GetRoleID(),stBattleTarget.GetRoleID(),
                            iTreasureID));
                return 0;
            }

            iBaseVal = 0;
            iChgByLvl = stSkillEffect.GetData() * iDistance;
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_GET_HURT://光荣之手
        {
            iBaseVal = stConfigData.GetData();
            iChgByLvl = stSkillEffect.GetData() * stStatusObj._iAddNum;
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_LOW_BLOOD://时间沙漏
        {
            iBaseVal = stConfigData.GetData();
            iChgByLvl = stSkillEffect.GetData();
            stStatusObj._iAuxData = 1;
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_SOLOMON_KEY://所罗门的钥匙
        {
            iBaseVal = stConfigData.GetData();
            iChgByLvl = stStatusObj._iAuxData + 1;
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_FATE_DICE://命运之骰
        {
            iBaseVal = stConfigData.GetData();
            iChgByLvl = stSkillEffect.GetData();
        }
        break;
    case CTreasureMgr::TREASURE_CFG_ID_SELF_DIE://厄运水晶球
        {
            iBaseVal = stConfigData.GetData();
            iChgByLvl = stStatusObj._iAuxData + 1;
        }
        break;
    default:
        {
            CT_WARNING(("unknown treasure config id(%d) when output video",
                        iTreasureID));
        }
        return 0;
    }

    CT_BATTLE(("秘宝日志:角色(%d)目标(%d)秘宝(%d)基础值(%d)等级制(%d)",
               stBattleRole.GetRoleID(),stBattleTarget.GetRoleID(),iTreasureID,
               iBaseVal, iChgByLvl));

    CMainCtrl::m_pstMain->m_stBattleMgr.StatusBattleVideo(
        stBattleRole.GetRoleID(), iTreasureID, iBaseVal, iChgByLvl);

    bHaveTriggerVideo = true;

    return 0;
}

int CStatusMgr::StatusMountVideo(CStatusCfgData& stCfgData,
        CBattleRole& stBattleRole, CBattleRole& stBattleTarget,
        CStatusObj& stStatusObj, bool& bHaveTriggerMount)
{
    if (STATUS_SOURCE_OBJ_MOUNT != stStatusObj._iSrcType)
    {
        return 0;
    }

    int iIndex = 0;
    int iStatusID = stStatusObj._iResID;
    int iMountID = (int)stStatusObj._uiSrcResID;

    iIndex = FindStatusCfg(iStatusID);
    if (iIndex < 0)
    {
        CT_RETURN(ERROR_STATUS_EMPTY_CFG);
    }

    //CStatusCfgData& stConfigData = GetStatusCfg(iIndex);

    iIndex = FindSkillEffect(iStatusID);
    if (iIndex < 0)
    {
        CT_RETURN(ERROR_STATUS_SKILL_EFF_EMPTY);
    }

    CSkillEffect& stSkillEffect = GetSkillEffect(iIndex);

    int iBaseVal = 0;
    int iChgByLvl = stSkillEffect.GetData();
    if (iChgByLvl < 0)
    {
        iChgByLvl = 0 - iChgByLvl;
    }

    CT_BATTLE(("坐骑日志:角色(%d)目标(%d)坐骑(%d)基础值(%d)等级制(%d)",
        stBattleRole.GetRoleID(),stBattleTarget.GetRoleID(),iMountID,iBaseVal,
        iChgByLvl));

    CMainCtrl::m_pstMain->m_stBattleMgr.StatusMountVideo(
        stBattleRole.GetRoleID(), iMountID, iBaseVal, iChgByLvl);

    bHaveTriggerMount = true;

    return 0;
}

int CStatusMgr::StatusSkillAffectRoleAttr(CBattleRole& stBattleRole,
        CBattleRole& stBattleTarget, CStatusCfgData& stCfgData,
        CStatusObj& stStatusObj, bool& bNeedTrigger)
{
    bNeedTrigger = false;

    int iData = stCfgData.GetData();
    if (iData <= 0)
    {
        CT_WARNING(("status(%d) data(%d) error",stCfgData.GetResID(),iData));
        return 0;
    }

    int iValueType = stCfgData.GetValueType();
    int iTriggerWay = stCfgData.GetTriggerWay();

    if (iValueType != CSkillEffect::SKILL_STAT_VAL_NUM &&
        iValueType != CSkillEffect::SKILL_STAT_VAL_RATE)
    {
        CT_WARNING(("status(%d) value type(%d) error",stCfgData.GetResID(),
                    iValueType));
        return 0;
    }

    CT_BATTLE(("状态属性条件检查:角色(%d) 目标(%d) 触发方式(%d) 数据类型(%d)" \
               " 数据(%d) 辅助值 (%d)",
               stBattleRole.GetRoleID(),stBattleTarget.GetRoleID(),
               iTriggerWay,iValueType,iData, stCfgData.GetAuxData()));

    if (stStatusObj._iAuxData < 0)
    {
        stStatusObj._iAuxData = 0;
    }

    double dRatio = 0.0;
    int iChgValue = 0;
    int iChgRatio = 0;//千分比
    int iNowRatio = BATTLE_RATE_SKILL_PERCENT;//千分比
    int iNowValue = 0;
    int iAttrMax = 0;
    int iChgTotal = 0;

    switch (stCfgData.GetAuxData())
    {
    case CSkillEffect::SKILL_SUB_STAT_COURAGE://勇气
        {
            iNowValue = stBattleRole.GetCourage();
            iAttrMax = stBattleRole.GetCourageMax();
            if (STATUS_TRIGGER_OBJ_ATTR_LIMIT == iTriggerWay ||
                STATUS_TRIGGER_TURN_ACT_OBJ_LIMIT == iTriggerWay ||
                STATUS_TRIGGER_CALC_ATK_OBJ_LIMIT == iTriggerWay)
            {
                iNowValue = stBattleTarget.GetCourage();
                iAttrMax = stBattleTarget.GetCourageMax();
            }

            iChgValue = iAttrMax - iNowValue;

            if (iAttrMax <= 0)
            {
                CT_BATTLE(("勇气最大值为0 直接返回"));
                return 0;
            }

            dRatio = iChgValue * 1.0;
            dRatio /= (iAttrMax * 1.0);
            iChgRatio = (int)(dRatio * BATTLE_RATE_SKILL_PERCENT);

            dRatio = iNowValue * 1.0;
            dRatio /= (iAttrMax * 1.0);
            iNowRatio = (int)(dRatio * BATTLE_RATE_SKILL_PERCENT);
        }
        break;
    case CSkillEffect::SKILL_SUB_STAT_ANGER://怒气
        {
            if (stBattleRole.GetUseAnger() > stBattleRole.GetAnger())
            {
                iNowValue = stBattleRole.GetUseAnger();
            }
            else
            {
                iNowValue = stBattleRole.GetAnger();
            }
            iAttrMax = stBattleRole.GetAngerMax();
            if (STATUS_TRIGGER_OBJ_ATTR_LIMIT == iTriggerWay ||
                STATUS_TRIGGER_TURN_ACT_OBJ_LIMIT == iTriggerWay ||
                STATUS_TRIGGER_CALC_ATK_OBJ_LIMIT == iTriggerWay)
            {
                iNowValue = stBattleTarget.GetAnger();
                iAttrMax = stBattleTarget.GetAngerMax();
            }

            iChgValue = iAttrMax - iNowValue;

            if (iAttrMax <= 0)
            {
                CT_BATTLE(("怒气最大值为0 直接返回"));
                return 0;
            }

            dRatio = iChgValue * 1.0;
            dRatio /= (iAttrMax * 1.0);
            iChgRatio = (int)(dRatio * BATTLE_RATE_SKILL_PERCENT);

            dRatio = iNowValue * 1.0;
            dRatio /= (iAttrMax * 1.0);
            iNowRatio = (int)(dRatio * BATTLE_RATE_SKILL_PERCENT);
        }
        break;
    case CSkillEffect::SKILL_SUB_STAT_HP://生命
        {
            iNowValue = stBattleRole.GetHP();
            iAttrMax = stBattleRole.GetHPMax();
            if (STATUS_TRIGGER_OBJ_ATTR_LIMIT == iTriggerWay ||
                STATUS_TRIGGER_TURN_ACT_OBJ_LIMIT == iTriggerWay ||
                STATUS_TRIGGER_CALC_ATK_OBJ_LIMIT == iTriggerWay)
            {
                iNowValue = stBattleTarget.GetHP();
                iAttrMax = stBattleTarget.GetHPMax();
            }

            iChgValue = iAttrMax - iNowValue;

            if (iAttrMax <= 0)
            {
                return 0;
            }

            dRatio = iChgValue * 1.0;
            dRatio /= (iAttrMax * 1.0);
            iChgRatio = (int)(dRatio * BATTLE_RATE_SKILL_PERCENT);

            dRatio = iNowValue * 1.0;
            dRatio /= (iAttrMax * 1.0);
            iNowRatio = (int)(dRatio * BATTLE_RATE_SKILL_PERCENT);
        }
        break;
    default:
        {
            CT_WARNING(("status(%d) aux data(%d) unknow!",
                        stCfgData.GetResID(),stCfgData.GetAuxData()));
        }
        return 0;
    }

    //自身属性改变时触发
    if (STATUS_TRIGGER_SELF_ATTR_CHG == iTriggerWay)
    {
        iChgTotal = iAttrMax - iNowValue;

        if (iChgTotal < stStatusObj._iAuxData)
        {
            stStatusObj._iAuxData = iChgTotal;
            return 0;
        }

        if (CSkillEffect::SKILL_STAT_VAL_NUM == iValueType)
        {
            stStatusObj._iAddNum =
                (iChgTotal - stStatusObj._iAuxData) / iData;

            if (stStatusObj._iAddNum > 0)
            {
                bNeedTrigger = true;
                stStatusObj._iAuxData += (stStatusObj._iAddNum * iData);
            }
        }
        else if (CSkillEffect::SKILL_STAT_VAL_RATE == iValueType)
        {
            dRatio =  iData * 1.0;
            dRatio /= BATTLE_RATE_SKILL_PERCENT;
            iData = (int)(dRatio * iAttrMax);

            stStatusObj._iAddNum =
                (iChgTotal - stStatusObj._iAuxData) / iData;

            if (stStatusObj._iAddNum > 0)
            {
                bNeedTrigger = true;
                stStatusObj._iAuxData += (stStatusObj._iAddNum * iData);
            }
        }
    }
    //自身属性临界时触发
    //目标属性临界时触发
    //回合行动时触发 攻击者移动后 发出技能效果前 要求检查目标临界值
    //计算伤害时触发 要求检查目标临界值
    else if (STATUS_TRIGGER_SELF_ATTR_LIMIT == iTriggerWay ||
             STATUS_TRIGGER_OBJ_ATTR_LIMIT == iTriggerWay ||
             STATUS_TRIGGER_TURN_ACT_OBJ_LIMIT == iTriggerWay ||
             STATUS_TRIGGER_CALC_ATK_OBJ_LIMIT == iTriggerWay)
    {
        if (CSkillEffect::SKILL_STAT_VAL_NUM == iValueType)
        {
            if (iNowValue <= iData)
            {
                bNeedTrigger = true;
            }
        }
        else if (CSkillEffect::SKILL_STAT_VAL_RATE == iValueType)
        {
            if (iNowRatio <= iData)
            {
                bNeedTrigger = true;
            }
        }
    }

    CT_BATTLE(("属性最大值(%d) 当前值(%d) 当前率(%d) 改变值(%d) 改变率(%d)" \
        " 是否触发(%d)",iAttrMax,iNowValue,iNowRatio,iChgValue,iChgRatio,
        bNeedTrigger));

    return 0;
}

int CStatusMgr::StatusSkillAffect(CBattleRole& stBattleRole, int iTriggerWay,
        int iAttrType, int iAuxAddNum)
{
#if 0
    //反击计算阶段 预执行技能阶段 各种能力都不生效
    if (CBattleRules::BATTLE_RULE_STAT_HIT_BACK ==
            CMainCtrl::m_pstMain->m_stBattleMgr.GetRuleStat() ||
        CBattleRules::BATTLE_RULE_STAT_PRE_SKILL ==
            CMainCtrl::m_pstMain->m_stBattleMgr.GetRuleStat())
    {
        return 0;
    }
#endif
    //预执行技能阶段 各种能力都不生效
    if (CBattleRules::BATTLE_RULE_STAT_PRE_SKILL ==
            CMainCtrl::m_pstMain->m_stBattleMgr.GetRuleStat())
    {
        return 0;
    }

    //暂时状态宿主已死亡不计算状态效果
    if (stBattleRole.HasDead() && STATUS_TRIGGER_SELF_DIE != iTriggerWay
            && STATUS_TRIGGER_SELF_DIE_OR_LIFE != iTriggerWay
            && STATUS_TRIGGER_SELF_DIE_ALL_DIE != iTriggerWay)
    {
        return 0;
    }
    
    int iRet = 0;
    int iIndex = 0;
    int iRandom = 0;
    int iBattleID = 0;
    int iActType = CMainCtrl::m_pstMain->m_stBattleMgr.GetBattleActType();

    bool bNeedTrigger = false;
    bool bAddRoleSkill = false;
    bool bChgSkillAffect = false;
    bool bExecSkillAffect = false;
    bool bHaveTriggerVideo = false;
    bool bHaveTriggerMount = false;

    unsigned int uiSkillAffectID = 0;

    CRoleSkillUnit stSkillUnit;
    CStatusObj stStatusObjTmp;
    CSkillAffect stSkillAffectTmp;

    MAP_GRID_MULTI stMapGridMulti;

    if (iAuxAddNum < 0)
    {
        iAuxAddNum = 0;
    }
    if (iTriggerWay <= 0)
    {
        CT_RETURN(ERROR_STATUS_TRIGGER_WAY);
    }

    CStatusList& stStatusList = stBattleRole.GetStatusList();

    for (int i = 0; i < stStatusList._astStatus.Size(); ++i)
    {
        CStatusObj& stStatusObj = stStatusList._astStatus[i];

        iIndex = FindStatusCfg(stStatusObj._iResID);
        if (iIndex < 0)
        {
            CT_RETURN(ERROR_STATUS_EMPTY_CFG);
        }

        CStatusCfgData& stCfgData = GetStatusCfg(iIndex);

        if (stCfgData.GetTriggerWay() != iTriggerWay)
        {
            continue;
        }

        if (stCfgData.GetActType() != 0 && stCfgData.GetActType() != iActType)
        {
            continue;
        }

        iRandom = CBattleRandom::GetRand(BATTLE_RATE_SKILL_PERCENT);
        if (iRandom > stCfgData.GetTriggerRate())
        {
            CT_BATTLE(("角色(%d)状态(%d)类型(%d)宿主(%u)机率(%d)概率结果(%d)",
                       stBattleRole.GetRoleID(),stStatusObj._iResID,
                       stStatusObj._iSrcType,stStatusObj._uiSrcResID,
                       stCfgData.GetTriggerRate(),iRandom));
            continue;
        }
        else
        {
            CT_BATTLE(("角色(%d)状态(%d)类型(%d)宿主(%u)机率(%d)概率结果(%d)",
                       stBattleRole.GetRoleID(),stStatusObj._iResID,
                       stStatusObj._iSrcType,stStatusObj._uiSrcResID,
                       stCfgData.GetTriggerRate(),iRandom));
        }

        if (STATUS_TRIGGER_SELF_ATTR_CHG == iTriggerWay ||//自身属性改变时触发
            STATUS_TRIGGER_SELF_ATTR_LIMIT == iTriggerWay)//自身属性临界时触发
        {
            if (stCfgData.GetAuxData() != iAttrType)
            {
                continue;
            }

            StatusSkillAffectRoleAttr(stBattleRole, stBattleRole, stCfgData,
                stStatusObj, bNeedTrigger);

            if (!bNeedTrigger)
            {
                continue;
            }
        }
        else if (STATUS_TRIGGER_OBJ_ATTR_LIMIT == iTriggerWay)//目标属性临界时触发
        {
            if (stCfgData.GetAuxData() != iAttrType)
            {
                continue;
            }
        }
        else if (STATUS_TRIGGER_NORMAL_SKILL_HIT == iTriggerWay ||//普通攻击命中时触发
                 STATUS_TRIGGER_NORMAL_SKILL_DOUBLE == iTriggerWay)//普通攻击暴击时触发
        {
            if (CSkill::SKILL_TYPE_NORMAL !=
                    CMainCtrl::m_pstMain->m_stBattleMgr.GetSkillType())
            {
                continue;
            }
        
        }
        else if (STATUS_TRIGGER_CAST_MAGIC_SKILL == iTriggerWay)//发动幻化技能时触发
        {
            if (CSkill::SKILL_TYPE_MAGIC !=
                    CMainCtrl::m_pstMain->m_stBattleMgr.GetSkillType())
            {
                continue;
            }
        }
        else if (STATUS_TRIGGER_SELF_DIE_ALL_DIE == iTriggerWay)
        {
            for (int k = 0;
                 k < CMainCtrl::m_pstMain->m_stBattleMgr.GetBattleRoleCount();
                 ++k)
            {
                CBattleRole& stBattleTemp =
                    CMainCtrl::m_pstMain->m_stBattleMgr.GetBattleRole(k);
                if (stBattleRole.IsLeft() == stBattleTemp.IsLeft() &&
                    !stBattleTemp.HasDead())
                {
                    return 0;
                }
            }

            if (stBattleRole.IsLeft())
            {
                CMainCtrl::m_pstMain->m_stBattleMgr.SetRightDeadBomb(false);
            }
            else
            {
                CMainCtrl::m_pstMain->m_stBattleMgr.SetRightDeadBomb(true);
            }
        }

        //这里判断触发次数上限
        if (stCfgData.GetTriggerTime() > 0)
        {
            if (stStatusObj._iTriTime >= stCfgData.GetTriggerTime())
            {
                continue;
            }
            else
            {
                ++stStatusObj._iTriTime;
            }
        }

        bAddRoleSkill = false;
        bChgSkillAffect = false;
        bExecSkillAffect = false;

        iIndex = FindSkillAffect(stStatusObj._iResID);
        if (iIndex < 0)
        {
            CT_TRACE(("status(%d) don't deal skill affect",
                      stStatusObj._iResID));
            continue;
        }
        
        CSkillAffect& stSkillAffect = GetSkillAffect(iIndex);
    
        iIndex = FindCfgSkillEffect(stStatusObj._iResID);
        if (iIndex >= 0)
        {
            CSkillEffect& stSkillEffect = GetCfgSkillEffect(iIndex);

            if (CSkillEffect::SKILL_STAT_RANDOM == stSkillEffect.GetStatType())
            {
                stStatusObjTmp = stStatusObj;

                stSkillAffectTmp.Clear();
                stSkillAffectTmp.AddSkillEffect(stSkillEffect);

                CMainCtrl::m_pstMain->m_stBattleMgr.StatusSkillEffect(
                    stBattleRole, stBattleRole, stSkillAffectTmp,
                    stStatusObjTmp, iAuxAddNum);

                CT_BATTLE(("角色(%d)状态(%d)随机特效(%u)随机结果(%d)",
                           stBattleRole.GetRoleID(),stStatusObj._iResID,
                           stSkillEffect.GetID(),stStatusObjTmp._iAuxData));

                stStatusObj._iAuxData = stStatusObjTmp._iAuxData;

                if (stStatusObjTmp._iAuxData >= 0 &&
                        stStatusObjTmp._iAuxData < 
                            stSkillAffect.GetSkillEffectSize())
                {
                    stSkillAffectTmp.Clear();
                    stSkillAffectTmp.AddSkillEffect(
                        stSkillAffect.GetSkillEffect(stStatusObjTmp._iAuxData));
                    bChgSkillAffect = true;
                }

                if (stStatusObjTmp._iAuxData >= 0 &&
                        stStatusObjTmp._iAuxData < stCfgData.GetAffectIDSize())
                {
                    uiSkillAffectID =
                        stCfgData.GetAffectID(stStatusObjTmp._iAuxData);

                    iIndex = CMainCtrl::m_pstMain->m_stSkillMgr.FindSkillAffCfg(
                        uiSkillAffectID);
                    if (iIndex >= 0)
                    {
                        stSkillAffectTmp =
                            CMainCtrl::m_pstMain->m_stSkillMgr.GetSkillAffCfg(
                                iIndex);
                        bChgSkillAffect = true;
                    }
                }

                if (stStatusObjTmp._iAuxData >= 0 &&
                        stStatusObjTmp._iAuxData < stCfgData.GetSkillIDSize())
                {
                    //保存选择的技能ID
                    stSkillUnit.Clear();
                    stSkillUnit.SetTurn(stCfgData.GetData());
                    stSkillUnit.SetRoleID(stBattleRole.GetRoleID());
                    stSkillUnit.SetSkillID(
                        stCfgData.GetSkillID(stStatusObjTmp._iAuxData));

                    bAddRoleSkill = true;
                }
                
                if (CSkillEffect::SKILL_SUB_STAT_EXEC_AFFECT ==
                        stSkillEffect.GetSubType())
                {
                    bExecSkillAffect = true;
                }
            }
        }

        if (stSkillAffect.GetSkillEffectSize() <= 0)
        {
            CT_WARNING(("status(%d) skill affect(%u) skill effect empty",
                        stStatusObj._iResID,stSkillAffect.GetID()));
            continue;
        }

        iRet = CMainCtrl::m_pstMain->m_stBattleMgr.StatusTargetChoose(
            stBattleRole, stSkillAffect, stMapGridMulti);
        if (iRet)
        {
            CT_WARNING(("status(%d) skill affect(%u) target choose error(%d)",
                        stStatusObj._iResID, stSkillAffect.GetID(), iRet));
            continue;
        }

        if (stMapGridMulti.Size() <= 0)
        {
            CT_TRACE(("status(%d) skill affect(%u) target empty",
                      stStatusObj._iResID, stSkillAffect.GetID()));
            continue;
        }

        CT_BATTLE(("角色(%d)状态(%d)类型(%d)宿主(%u)技能功能(%u)的目标列表",
                   stBattleRole.GetRoleID(),stStatusObj._iResID,
                   stStatusObj._iSrcType,stStatusObj._uiSrcResID,
                   stSkillAffect.GetID()));
        DumpStatusTarget(stMapGridMulti);

        bHaveTriggerVideo = false;
        bHaveTriggerMount = false;

        //执行SkillAffect功能
        for (int j = 0; j < stMapGridMulti.Size(); ++j)
        {
            iBattleID = stMapGridMulti[j].GetRoleID();
            if (!CMainCtrl::m_pstMain->m_stBattleMgr.IsValidRoleID(iBattleID))
            {
                CT_WARNING(("battle role id(%d) invalid",iBattleID));
                continue;
            }

            CBattleRole& stBattleTarget =
                CMainCtrl::m_pstMain->m_stBattleMgr.GetBattleRole(iBattleID);

                //目标属性临界时触发
            if (STATUS_TRIGGER_OBJ_ATTR_LIMIT == iTriggerWay ||
                //回合行动时触发 攻击者移动后 发出技能效果前 要求检查目标临界值
                STATUS_TRIGGER_TURN_ACT_OBJ_LIMIT == iTriggerWay ||
                //计算伤害时触发 要求检查目标临界值
                STATUS_TRIGGER_CALC_ATK_OBJ_LIMIT == iTriggerWay)
            {
                StatusSkillAffectRoleAttr(stBattleRole, stBattleTarget,
                    stCfgData, stStatusObj, bNeedTrigger);

                if (!bNeedTrigger)
                {
                    continue;
                }
            }

            //保证多个目标也只输出一条日志 这里先于SkillAffect执行前输出
            if (!bHaveTriggerVideo && stCfgData.GetAppearType())
            {
                StatusBattleVideo(stCfgData, stBattleRole, stBattleTarget,
                    stStatusObj, bHaveTriggerVideo);
            }
            if (!bHaveTriggerMount && stCfgData.GetAppearType())
            {
                StatusMountVideo(stCfgData, stBattleRole, stBattleTarget,
                    stStatusObj, bHaveTriggerMount);
            }

            if (bChgSkillAffect)
            {
                if (bExecSkillAffect)
                {
                    CMainCtrl::m_pstMain->m_stBattleMgr.StatusSkillEffect(
                        stBattleRole, stBattleTarget, stSkillAffect,
                        stStatusObj, iAuxAddNum);
                }
#ifdef _DEBUG
                if (stSkillAffectTmp.GetSkillEffectSize() > 0)
                {
                    CTSizeString<64> sVideo;
                    for (int k = 0; k < stSkillAffectTmp.GetSkillEffectSize();
                            ++k)
                    {
                        sVideo.Cat("%u ",stSkillAffectTmp.GetSkillEffectID(k));
                    }

                    CT_BATTLE(("角色(%d)状态(%d)修正后的技能功能(%u)特效数量" \
                               "(%d)特效序列(%s)",stBattleRole.GetRoleID(),
                               stStatusObj._iResID,stSkillAffectTmp.GetID(),
                               stSkillAffectTmp.GetSkillEffectSize(),
                               sVideo.Get()));
                }
#endif
                iRet = CMainCtrl::m_pstMain->m_stBattleMgr.StatusSkillEffect(
                    stBattleRole, stBattleTarget, stSkillAffectTmp, stStatusObj,
                    iAuxAddNum);
                if (iRet)
                {
                    CT_WARNING(("battle id(%d) deal skill affect(%u) error(%d)",
                                iBattleID,stSkillAffectTmp.GetID(),iRet));
                }
            }
            else
            {
                iRet = CMainCtrl::m_pstMain->m_stBattleMgr.StatusSkillEffect(
                    stBattleRole, stBattleTarget, stSkillAffect, stStatusObj,
                    iAuxAddNum);
                if (iRet)
                {
                    CT_WARNING(("battle id(%d) deal skill affect(%u) error(%d)",
                                iBattleID,stSkillAffect.GetID(),iRet));
                }
            }

            if (bAddRoleSkill)
            {
                stBattleTarget.AddSkillUnit(stSkillUnit);

                CT_BATTLE(("角色(%d)被角色(%d)状态(%d)施加预执行技能(%u)" \
                           "持续回合数(%d)技能来源(%d)",
                           stBattleTarget.GetRoleID(),stBattleRole.GetRoleID(),
                           stStatusObj._iResID,stSkillUnit.GetSkillID(),
                           stSkillUnit.GetTurn(),stSkillUnit.GetRoleID()));
            }

            //保证多个目标也只输出一条日志 这里等待SkillAffect执行后输出
            if (!bHaveTriggerVideo && !stCfgData.GetAppearType())
            {
                StatusBattleVideo(stCfgData, stBattleRole, stBattleTarget,
                    stStatusObj, bHaveTriggerVideo);
            }
            if (!bHaveTriggerMount && !stCfgData.GetAppearType())
            {
                StatusMountVideo(stCfgData, stBattleRole, stBattleTarget,
                    stStatusObj, bHaveTriggerMount);
            }
        }
    }

    return 0;
}

int CStatusMgr::StatusSkillAffect(CBattleRole& stBattleRole, int iTriggerWay,
        int iAuxAddNum)
{
    return StatusSkillAffect(stBattleRole, iTriggerWay, 0, iAuxAddNum);
}

//调试用 输出大量日志
void CStatusMgr::DumpStatusTarget(MAP_GRID_MULTI& stMapGridMulti)
{
    CT_BATTLE(("%-18s = %d", "状态目标总数", stMapGridMulti.Size()));
    for (int i = 0; i < stMapGridMulti.Size(); ++i)
    {
        CT_BATTLE(("第(%d)目标 ID = %d",i+1,stMapGridMulti[i].GetRoleID()));
    }
}

void CStatusMgr::DumpStatusObj(CStatusObj& stStatusObj)
{
    CT_BATTLE(("状态ID(%d) 叠加层数(%d) 辅助数据(%d) 来源类型(%d) 来源ID(%u)",
               stStatusObj._iResID,stStatusObj._iAddNum,stStatusObj._iAuxData,
               stStatusObj._iSrcType,stStatusObj._uiSrcResID));
}

void CStatusMgr::DumpStatusList(CStatusList& stStatusList)
{
    CT_BATTLE(("状态数量(%d)", stStatusList._astStatus.Size()));
    if (stStatusList._astStatus.Size() > 0)
    {
        for (int i = 0; i < stStatusList._astStatus.Size(); ++i)
        {
            DumpStatusObj(stStatusList._astStatus[i]);
        }
    }
}

//状态ID存在性的简单检查
int CStatusMgr::IsValidStatusID(int iStatusID)
{
    if (iStatusID == 0)
    {
        return 0;
    }
    else if (iStatusID < 0)
    {
        return ERROR_STATUS_OVER_RESID;
    }

    if (FindStatusCfg(iStatusID) < 0)
    {
        CT_ERROR(("status config(%d) not exist",iStatusID));
        CT_RETURN(ERROR_STATUS_EMPTY_CFG);
    }

    return 0;
}

//状态组存在性的简单检查
int CStatusMgr::IsValidStatusGroup(int iGroupID)
{
    if (iGroupID == 0)
    {
        return 0;
    }
    else if (iGroupID < 0)
    {
        return ERROR_STATUS_GROUP_OVER_RESID;
    }

    if (FindStatusGroup(iGroupID) < 0)
    {
        CT_ERROR(("status group(%d) not exist",iGroupID));
        CT_RETURN(ERROR_STATUS_GROUP_EMPTY_CFG);
    }

    return 0;
}

